package drds.common.db.xml_mapping.script.xml_tags;

import drds.common.db.xml_mapping.parameter_and_result_value_type.SimpleTypeRegistry;
import drds.common.db.xml_mapping.parsing.GenericTokenParser;
import drds.common.db.xml_mapping.parsing.TokenHandler;
import drds.common.db.xml_mapping.script.ScriptingException;

import java.util.regex.Pattern;


public class Text implements DynamicNode {
  private final String text;
  private final Pattern injectionFilter;

  public Text(String text) {
    this(text, null);
  }

  public Text(String text, Pattern injectionFilter) {
    this.text = text;
    this.injectionFilter = injectionFilter;
  }

  public boolean isDynamic() {
    DynamicCheckerTokenParser checker = new DynamicCheckerTokenParser();
    GenericTokenParser parser = createGenericTokenParser(checker);
    parser.parse(text);
    return checker.isDynamic();
  }

  @Override
  public boolean apply(DynamicNodeContext dynamicNodeContext) {
    GenericTokenParser genericTokenParser = createGenericTokenParser(new BindingTokenParser(dynamicNodeContext, injectionFilter));
    dynamicNodeContext.appendSql(genericTokenParser.parse(text));
    return true;
  }

  private GenericTokenParser createGenericTokenParser(TokenHandler tokenHandler) {
    return new GenericTokenParser("${", "}", tokenHandler);
  }

  private static class BindingTokenParser implements TokenHandler {

    private DynamicNodeContext context;
    private Pattern injectionFilter;

    public BindingTokenParser(DynamicNodeContext context, Pattern injectionFilter) {
      this.context = context;
      this.injectionFilter = injectionFilter;
    }

    @Override
    public String handleToken(String content) {
      Object parameter = context.getBindings().get("_parameter");
      if (parameter == null) {
        context.getBindings().put("value", null);
      } else if (SimpleTypeRegistry.isSimpleType(parameter.getClass())) {
        context.getBindings().put("value", parameter);
      }
      Object value = OgnlCache.getValue(content, context.getBindings());
      String srtValue = value == null ? "" : String.valueOf(value); // issue #274 return "" instead of "null"
      checkInjection(srtValue);
      return srtValue;
    }

    private void checkInjection(String value) {
      if (injectionFilter != null && !injectionFilter.matcher(value).matches()) {
        throw new ScriptingException("Invalid input. Please conform to regex" + injectionFilter.pattern());
      }
    }
  }

  private static class DynamicCheckerTokenParser implements TokenHandler {

    private boolean isDynamic;

    public DynamicCheckerTokenParser() {
      // Prevent Synthetic Access
    }

    public boolean isDynamic() {
      return isDynamic;
    }

    @Override
    public String handleToken(String content) {
      this.isDynamic = true;
      return null;
    }
  }

}
